<template>
  <div>
    <EmptyStatus
      v-if="arrangedAirportData.length == 0 && momentIndexMax <= 0"
      modelName="扇区/进出点"
    />
    <div v-else>
      <!-- ConfigBar -->
      <div v-if="config.configBarPinned" class="config-bar-placeholder"></div>
      <el-card
        :class="[
          config.configBarPinned ? 'config-bar-pinned' : 'config-bar',
          config.configBarPinned && !commonStore.showSidebar
            ? 'config-bar-pinned-full'
            : '',
        ]"
        shadow="hover"
      >
        <div style="display: flex; align-items: center">
          <!-- timeline slider -->
          <el-slider
            style="margin-right: 18px"
            v-model="selectedMomentIndex"
            :min="0"
            :max="momentIndexMax"
            :step="1"
            show-stops
            :format-tooltip="getTooltip"
            :marks="momentMarkers"
            @change="handleChange"
            @mousedown="handleDragging"
            @mouseup="handleDragging"
            @mousemove="handleDragging"
          />
          <el-button
            round
            :type="isEqualedComputingOption ? 'primary' : 'danger'"
            size="small"
            @click="config.showConfig = !config.showConfig"
          >
            <span style="padding-right: 6px">{{
              selectedMomentValue.split(" ")[1]
            }}</span>
            <el-icon :class="[autoGoTimer == null ? '' : 'is-loading']">
              <Tools />
            </el-icon>
          </el-button>
        </div>
        <transition name="el-fade-in">
          <div
            v-if="config.showConfig"
            v-dragMove="{
              DragButton: '.config-header',
              DragWindow: '.config-window',
            }"
          >
            <div
              :class="[
                'config-window',
                commonStore.darkMode
                  ? 'config-window-dark'
                  : 'config-window-light',
              ]"
            >
              <div class="config-header">
                <span>切片设置</span>
                <el-button
                  link
                  size="large"
                  icon="close"
                  @click="config.showConfig = false"
                ></el-button>
              </div>
              <div class="config-body" v-if="config.showConfig">
                <div style="font-size: 12px; text-align: center">
                  <div>
                    <span>
                      {{ dayjs(selectedTimestamp).format("MM/DD HH:mm") }}
                    </span>
                    <span style="padding: 0 12px">至</span>
                    <span>
                      {{
                        dayjs(
                          selectedTimestamp + config.dataStep * 900000
                        ).format("MM/DD HH:mm")
                      }}
                    </span>
                  </div>
                  <div>
                    <el-button
                      style="margin-top: 12px"
                      text
                      size="small"
                      type="primary"
                      @click="jumpToCurrentMoment"
                      :disabled="
                        currentMomentIndex != -1 &&
                        currentMomentIndex == selectedMomentIndex
                      "
                    >
                      <el-icon><RefreshRight /></el-icon>
                      <span>当前</span>
                    </el-button>
                    <el-button
                      style="margin-top: 12px"
                      text
                      size="small"
                      :type="autoGoTimer != null ? 'success' : 'primary'"
                      @click="autoGo"
                    >
                      <el-icon><CaretRight /></el-icon>
                      <span>播放</span>
                    </el-button>
                  </div>
                </div>
                <el-divider />
                <el-form size="small">
                  <el-form-item label="时间粒度">
                    <el-radio-group
                      v-model="config.dataGranularity"
                      @change="handleGranularityChange"
                    >
                      <el-radio-button :value="1">15分钟</el-radio-button>
                      <el-radio-button :value="2">30分钟</el-radio-button>
                      <el-radio-button :value="4">60分钟</el-radio-button>
                    </el-radio-group></el-form-item
                  >
                  <el-form-item label="刻度间隔">
                    <el-radio-group
                      v-model="config.dataInterval"
                      @change="handleIntervalChange"
                    >
                      <el-radio-button :value="1">15分钟</el-radio-button>
                      <el-radio-button :value="2">30分钟</el-radio-button>
                      <el-radio-button :value="4">60分钟</el-radio-button>
                    </el-radio-group>
                  </el-form-item>
                  <el-form-item label="统计步长">
                    <el-radio-group
                      v-model="config.dataStep"
                      @change="handleStepChange"
                    >
                      <el-radio-button :value="1">15分钟</el-radio-button>
                      <el-radio-button :value="2">30分钟</el-radio-button>
                      <el-radio-button :value="4">60分钟</el-radio-button>
                    </el-radio-group>
                  </el-form-item>
                  <el-form-item label="播放速度">
                    <el-radio-group v-model="config.autoPlaySpeed">
                      <el-radio-button :value="500">0.5s</el-radio-button>
                      <el-radio-button :value="1000">1.0s</el-radio-button>
                      <el-radio-button :value="1500">1.5s</el-radio-button>
                      <el-radio-button :value="2000">2.0s</el-radio-button>
                    </el-radio-group>
                  </el-form-item>
                  <el-form-item label="时间轴">
                    <el-radio-group v-model="config.configBarPinned">
                      <el-radio :value="false">嵌入页面</el-radio>
                      <el-radio :value="true">固定并置顶</el-radio>
                    </el-radio-group>
                  </el-form-item>
                  <el-form-item label="计算模式">
                    <el-select
                      v-model="config.selectedComputingOption"
                      size="small"
                    >
                      <el-option value="" label="自动 (当前情况)"></el-option>
                      <el-option value="NN" label="双北×天北"></el-option>
                      <el-option
                        value="NNWJ"
                        label="双北×天北×温江"
                      ></el-option>
                      <el-option value="SS" label="双南×天南"></el-option>
                      <el-option
                        value="SSWJ"
                        label="双南×天南×温江"
                      ></el-option>
                      <el-option value="SN" label="双南×天北"></el-option>
                      <el-option
                        value="SNWJ"
                        label="双南×天北×温江"
                      ></el-option>
                      <el-option value="NS" label="双北×天南"></el-option>
                      <el-option
                        value="NSWJ"
                        label="双北×天南×温江"
                      ></el-option>
                    </el-select>
                    <el-tag
                      v-if="!isEqualedComputingOption"
                      type="danger"
                      style="width: 100%; margin-top: 6px"
                    >
                      <el-icon><WarningFilled /></el-icon>
                      <span>非当前实际模式</span>
                    </el-tag>
                  </el-form-item>
                  <el-form-item label="扇区颜色">
                    <el-button
                      type="primary"
                      size="small"
                      text
                      @click="sectorColorSetter.open()"
                    >
                      <el-icon><Brush /></el-icon>
                      <span>设置扇区颜色</span>
                    </el-button>
                    <SectorColorSetter ref="sectorColorSetter" />
                  </el-form-item>
                </el-form>
              </div>
            </div>
          </div>
        </transition>
      </el-card>
      <el-card style="margin: 24px 16px 24px 16px" shadow="hover">
        <el-scrollbar>
          <div class="chart-container">
            <div style="min-width: 360px; min-height: 300px">
              <transition name="el-fade-in">
                <AirportChart
                  v-if="mountingList.airportChart"
                  :airportData="selectedAirportCell"
                />
              </transition>
            </div>
            <div class="chart-divider"></div>
            <div style="min-width: 360px; min-height: 300px">
              <transition name="el-fade-in">
                <PointChart
                  v-if="mountingList.pointChart"
                  :airportData="selectedAirportCell"
                />
              </transition>
            </div>
            <div class="chart-divider"></div>
            <div style="min-width: 360px; min-height: 300px">
              <transition name="el-fade-in">
                <SectorChart
                  v-if="mountingList.seatChart"
                  :seatData="seatData"
                  :dataStep="config.dataStep"
                />
              </transition>
            </div>
          </div>
        </el-scrollbar>
      </el-card>
      <el-card style="margin: 24px 16px 24px 16px" shadow="hover">
        <el-collapse-transition>
          <SankeyDiagram
            v-show="mountingList.sankeyDiagram"
            :sankeyData="sankeyData"
            ref="sankeyDiagram"
          />
        </el-collapse-transition>
      </el-card>
      <div style="margin: 24px 16px 24px 16px; display: flex">
        <el-card shadow="hover" style="width: 100%; margin-right: 24px">
          <div style="min-height: 640px">
            <transition name="el-fade-in">
              <SectorGraphic
                v-if="mountingList.seatGraphic"
                :seatData="seatData"
              />
            </transition>
          </div>
        </el-card>
        <el-card
          shadow="hover"
          :style="{
            width: rightBarWidth,
            minWidth: rightBarWidth,
            maxWidth: rightBarWidth,
          }"
        >
          <div style="min-height: 640px">
            <transition name="el-fade-in">
              <SectorController v-if="mountingList.sectorController" />
            </transition>
          </div>
        </el-card>
      </div>
    </div>
    <AlertView v-if="showAlert" alert-name="NTFM" />
  </div>
</template>

<script setup>
// import vue apis
import { ref, computed, nextTick, watch, onMounted, onUnmounted } from "vue";
import { ElNotification, ElMessage } from "element-plus";
import dayjs from "dayjs";

// import stores
import useFlowStore from "@/store/flow.js";
import useSeatStore from "@/store/seat.js";
import useActivityStore from "@/store/activity.js";
import useCommonStore from "@/store/common.js";

// import slert view
import AlertView from "@/components/Alert/index.vue";

// import utils
import {
  cumulate,
  arrange,
  prearrange,
  arrangeSector,
  policyCompute,
  arrangeSankey,
} from "../utils";

import dateFormat from "@/utils/dateFormat.js";

// import components
import EmptyStatus from "../EmptyStatus";
import AirportChart from "./AirportChart.vue";
import PointChart from "./PointChart.vue";
import SectorChart from "./SectorChart.vue";
import SectorGraphic from "./SectorGraphic.vue";
import SectorController from "./SectorController.vue";
import SectorColorSetter from "./SectorColorSetter.vue";
// import GeneralChart from "../GeneralChart";
import SankeyDiagram from "./SankeyDiagram.vue";

const flowStore = useFlowStore();
const commonStore = useCommonStore();
const activityStore = useActivityStore();
const seatStore = useSeatStore();

const showAlert = computed(() => flowStore.isStoped);

// components refs
const sectorColorSetter = ref();
const sankeyDiagram = ref();

// general config
const config = flowStore.chartConfig.advancedChart;
const handleGranularityChange = () => {
  config.dataStep = config.dataGranularity;
  config.dataInterval = config.dataGranularity;
  jumpToCurrentMoment();
};

const handleIntervalChange = () => {
  if (config.dataInterval > config.dataStep) {
    config.dataStep = config.dataInterval;
  }
  if (config.dataInterval != config.dataStep) {
    config.dataGranularity = 0;
  } else {
    config.dataGranularity = config.dataInterval;
  }
  jumpToCurrentMoment();
};

const handleStepChange = () => {
  if (config.dataInterval > config.dataStep) {
    config.dataInterval = config.dataStep;
  }
  if (config.dataInterval != config.dataStep) {
    config.dataGranularity = 0;
  } else {
    config.dataGranularity = config.dataStep;
  }
  jumpToCurrentMoment();
};

const rightBarWidth = ref("360px");
const clientWidth = computed(() => commonStore.getClientWidth);
const handlePinConfigBar = () => {
  config.configBarPinned = !config.configBarPinned;
  if (config.configBarPinned) {
    ElMessage({
      message: "时间轴已置顶显示",
      type: "warning",
    });
  } else {
    ElMessage({
      message: "时间轴已取消置顶",
    });
  }
};

// slider config
const selectedMomentIndex = ref(0);
const momentIndexMax = computed(() => arrangedAirportData.value.length - 1);
const getTooltip = () => selectedMomentValue.value;

const selectedMomentValue = computed(() => {
  if (arrangedAirportData.length == 0) {
    return "Empty!";
  } else if (
    selectedMomentIndex.value >= 0 &&
    selectedMomentIndex.value <= momentIndexMax.value
  ) {
    return arrangedAirportData.value[selectedMomentIndex.value].moment;
  } else {
    return "Invalid!";
  }
});

const selectedTimestamp = computed(() => {
  if (arrangedAirportData.length == 0) {
    return "Empty!";
  } else if (
    selectedMomentIndex.value >= 0 &&
    selectedMomentIndex.value <= momentIndexMax.value
  ) {
    return arrangedAirportData.value[selectedMomentIndex.value].timestamp;
  } else {
    return "Invalid!";
  }
});

const momentMarkers = computed(() => {
  let max = momentIndexMax.value;
  let mid = currentMomentIndex.value;
  let sel = selectedMomentIndex.value;
  if (max <= 0) {
    return [];
  } else {
    let marks = {};
    marks[0] = {
      label: arrangedAirportData.value[0].moment,
      style: {
        color: sel < mid ? "#1989FA" : "#6C6E72",
        fontSize: "10px",
        textAlign: "right",
        width: "128px",
      },
    };
    marks[max] = {
      label: arrangedAirportData.value[max].moment,
      style: {
        color: sel > mid ? "#1989FA" : "#6C6E72",
        fontSize: "10px",
        textAlign: "left",
        width: "128px",
      },
    };
    if (mid > -1)
      marks[mid] = {
        label: "当前", // arrangedAirportData.value[mid].moment,
        style: {
          color: sel == mid ? "#1989FA" : "#6C6E72",
          fontSize: "10px",
        },
      };
    return marks;
  }
});

const currentMomentIndex = computed(() => {
  if (momentIndexMax.value <= 0) return -1;
  for (let i = 0; i < momentIndexMax.value; i++) {
    let t = arrangedAirportData.value[i].timestamp;
    let t0 = new Date().getTime();
    if (t <= t0 && t + config.dataStep * 900000 > t0) {
      return i;
    }
  }
  return -1;
});

const jumpToCurrentMoment = () => {
  autoGoStop();
  let idx = selectedMomentIndex.value;
  let idx0 = currentMomentIndex.value;
  if (idx != idx0 && idx0 > -1) {
    selectedMomentIndex.value = idx0;
    return true;
  } else {
    return false;
  }
};

// selectedAirportCell
const selectedAirportCell = computed(() => {
  if (arrangedAirportData.length == 0) {
    return null;
  } else if (
    selectedMomentIndex.value >= 0 &&
    selectedMomentIndex.value <= momentIndexMax.value
  ) {
    return arrangedAirportData.value[selectedMomentIndex.value];
  } else {
    return null;
  }
});

// cumulatedRawData
const cumulatedRawData = computed(() => {
  let rawData = flowStore.rawData;
  if (!rawData || rawData.length == 0) return [];
  return cumulate(rawData, config.dataInterval, config.dataStep);
});

const tags = computed(() => flowStore.tags);
const begTime = computed(() => flowStore.begTime);

// arrangedAirportData
const arrangedAirportData = computed(() => {
  if (cumulatedRawData.value.length == 0) return [];
  let arrangedAirportData = arrange(
    cumulatedRawData.value,
    tags.value,
    begTime.value,
    config.dataInterval
    // ["airport", "type"]
  );
  arrangedAirportData = policyCompute(arrangedAirportData, config.dataStep);
  return arrangedAirportData;
});

// taggedData
const taggedData = computed(() => {
  if (cumulatedRawData.value.length == 0) return [];
  return prearrange(
    cumulatedRawData.value,
    tags.value,
    begTime.value,
    config.dataStep
  );
});

const selectedTagData = computed(() => {
  if (taggedData.length == 0) {
    return null;
  } else if (
    selectedMomentIndex.value >= 0 &&
    selectedMomentIndex.value <= momentIndexMax.value
  ) {
    return taggedData.value[selectedMomentIndex.value];
  } else {
    return null;
  }
});

const autoComputingOption = computed(() => {
  return activityStore.opMode;
  // let wj = "";
  // let dir = "NN";
  // for (let i = 0; i < activityStore.militaryStatus.length; i++) {
  //   let cell = activityStore.militaryStatus[i];
  //   wj =
  //     cell.arrField == "温江" || cell.depField == "温江" || cell.unit == "温江"
  //       ? "WJ"
  //       : "";
  // }
  // for (let i = 0; i < seatStore.seatStatusFull.length; i++) {
  //   let cell = seatStore.seatStatusFull[i];
  //   if (cell.seatType == "运行方向") {
  //     dir = cell.logicSectorCode;
  //   }
  // }
  // return dir + wj;
});

const isEqualedComputingOption = computed(() => {
  return computingOption.value === autoComputingOption.value;
});

const computingOption = computed(() => {
  if (config.selectedComputingOption == "") {
    return autoComputingOption.value;
  } else {
    return config.selectedComputingOption;
  }
});

const currentSeatCount = computed(() => {
  for (let i = 0; i < seatStore.seatStatusFull.length; i++) {
    let cell = seatStore.seatStatusFull[i];
    if (cell.seatType == "席位数量") {
      return cell.logicSectorCode;
    }
  }
  return 0;
});

const seatData = computed(() => {
  if (!selectedTagData || !selectedTagData.value || !selectedTagData.value.data)
    return null;
  return arrangeSector(
    selectedTagData.value.data,
    computingOption.value,
    flowStore.selectedSectorScheme.content
  );
});

// Added data for sankey giagram
const sankeyData = computed(() => {
  if (
    !selectedTagData ||
    !selectedTagData.value ||
    !selectedTagData.value.data
  ) {
    return null;
  } else {
    return arrangeSankey(
      selectedTagData.value.data,
      computingOption.value,
      flowStore.selectedSectorScheme.content
    );
  }
});

// timeline slider control

let autoGoTimer = ref(null);
const autoGo = () => {
  lastDrag = new Date().getTime();
  if (autoGoTimer.value != null) {
    clearInterval(autoGoTimer.value);
    autoGoTimer.value = null;
  } else {
    autoGoTimer.value = setInterval(() => {
      lastDrag = new Date().getTime();
      if (selectedMomentIndex.value == arrangedAirportData.value.length - 1) {
        selectedMomentIndex.value = 0;
      } else {
        selectedMomentIndex.value++;
      }
    }, config.autoPlaySpeed);
  }
};

const autoGoStop = () => {
  if (autoGoTimer.value != null) {
    clearInterval(autoGoTimer.value);
    autoGoTimer.value = null;
  }
};

const handleChange = () => {};

let lastDrag = new Date().getTime();
let isDragging = false;

const handleDragging = (event) => {
  if (event.type == "mousedown") {
    autoGoStop();
    isDragging = true;
    lastDrag = new Date().getTime();
  } else if (event.type == "mousemove") {
    if (isDragging) {
      lastDrag = new Date().getTime();
    }
  } else if (event.type == "mouseup") {
    lastDrag = new Date().getTime();
    isDragging = false;
  }
};

let jumpingTimeout = 30000;
const autoJump = () => {
  if (new Date().getTime() - lastDrag > jumpingTimeout) {
    if (jumpToCurrentMoment()) {
      ElMessage({
        showClose: true,
        message: "长时间未拖动时间轴，已自动跳转回当前时刻",
        duration: 10000,
      });
    }
  }
};

// Timeline driven actions
watch(
  () => [selectedMomentIndex.value],
  async () => {
    sankeyDiagram.value.refreshChart();
  }
);

// Rendering control
const mountingList = ref({
  pointChart: false,
  airportChart: false,
  seatChart: false,
  seatGraphic: false,
  sectorController: false,
  sankeyDiagram: false,
});

const delayMount = () => {
  for (let key in mountingList.value) {
    if (!mountingList.value[key]) {
      // console.log(key, "continue");
      mountingList.value[key] = true;
      return;
    }
  }
  clearInterval(mountingTimer);
};

let mountingTimer = null;
let mountingInterval = 300;
let jumpingTimer = null;
let jumpingInterval = 1000;

onMounted(() => {
  // autoJump();
  jumpToCurrentMoment();
  mountingTimer = setInterval(() => delayMount(), mountingInterval);
  jumpingTimer = setInterval(() => autoJump(), jumpingInterval);
});

onUnmounted(() => {
  if (mountingTimer) clearInterval(mountingTimer);
  if (autoGoTimer.value) clearInterval(autoGoTimer.value);
  clearInterval(jumpingTimer);
});
</script>

<style scoped>
.setting-title {
  margin: 12px 0;
  padding: 2px 0;
  background-color: rgba(128, 128, 128, 0.25);
  border: 1px solid rgba(128, 128, 128, 0.5);
  /* border-left: none; */
  /* border-right: none; */
  font-size: 12px;
  font-weight: bold;
  text-align: center;
}

.config-bar {
  margin: 24px 16px 24px 16px;
}

.config-bar-pinned {
  position: fixed;
  width: calc(100vw - 232px);
  top: 60px;
  margin: 24px 16px 24px 16px;
  z-index: 10;
  transition: all 0.3s ease-in-out;
}

.config-bar-pinned-full {
  width: calc(100vw - 32px);
}

.config-bar-placeholder {
  padding: 37px;
  margin: 24px 16px 24px 16px;
}

.pin-button {
  position: absolute;
  top: 0;
  right: 0;
  height: 20px;
  width: 20px;
  cursor: pointer;
}

.pin-button-light {
  color: gold;
}

.chart-container {
  min-width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.chart-divider {
  min-height: 280px;
  /* margin-top: 24px; */
  border-left: 1px dashed rgba(128, 128, 128, 0.25);
}

.config-window {
  z-index: 99;
  width: 300px;
  right: 16px;
  top: 182px;
  position: fixed;
  user-select: none;
  /* background-color: var(--el-color-info-light-9); */
  /* box-shadow: var(--el-box-shadow); */
  border-radius: 6px;
  border: 1px solid var(--el-border-color);
}

.config-window-dark {
  backdrop-filter: blur(15px);
  background-color: rgba(22, 22, 22, 0.75);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.75);
}

.config-window-light {
  backdrop-filter: blur(10px);
  background-color: rgba(233, 233, 233, 0.6);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25);
}

.config-body {
  padding: 24px;
}
.config-header {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  padding-right: 8px;
  color: var(--el-text-color-primary);
  border-bottom: 1px solid var(--el-border-color);
}
</style>
